%include "pm.inc"

%ifdef DOS_DEBUG
org 0100h
%else
org 07c00h
%endif

jmp LABEL_BEGIN

[SECTION .gdt]
LABEL_GDT: Descriptor 0, 0, 0
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_CR|DA_32
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C
LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW

GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1
    dd 0
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
SelectorData equ LABEL_DESC_DATA - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT

[SECTION .data1]
ALIGN 32
[BITS 32]
LABEL_DATA:
	_wSPValueInRealMode dw 0
DataLen equ $ - LABEL_DATA

[SECTION .idt]
ALIGN 32
[BITS 32]
LABEL_IDT:
%rep 10
	Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate
%endrep

IdtLen equ $ - LABEL_IDT
IdtPtr dw IdtLen - 1
	dd 0

[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, 0100h
	
	mov [LABEL_GO_BACK_TO_REAL + 3], ax
	mov [_wSPValueInRealMode], sp
	
	xor	eax, eax
	mov	ax, cs
	shl	eax, 4
	add	eax, LABEL_SEG_CODE32
	mov	word [LABEL_DESC_CODE32 + 2], ax
	shr	eax, 16
	mov	byte [LABEL_DESC_CODE32 + 4], al
	mov	byte [LABEL_DESC_CODE32 + 7], ah

	xor eax, eax
	mov ax, ds
	shl eax, 4
	add eax, LABEL_GDT
	mov dword [GdtPtr + 2], eax
	
	xor eax, eax
	mov ax, ds
	shl eax, 4
	add eax, LABEL_IDT
	mov dword [IdtPtr + 2], eax

	lgdt [GdtPtr]

	cli
	
	lidt [IdtPtr]

	in al, 92h
	or al, 00000010b
	out 92h, al

	mov eax, cr0
	or eax, 1
	mov cr0, eax

	jmp dword SelectorCode32:0

LABEL_REAL_ENTRY:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, [_wSPValueInRealMode]
	
	in al, 92h
	and al, 11111101b
	out 92h, al
	
	sti
%ifdef DOS_DEBUG
	mov ax, 4c00h
	int 21h
%else
	jmp $
%endif

[SECTION .s32]
[BITS 32]
LABEL_SEG_CODE32:	
	mov ax, SelectorData
	mov ds, ax
	mov	es, ax
	mov ax, SelectorVideo
	mov gs, ax

	call Init8259A
	int 05h
	
	jmp SelectorCode16:0
	
Init8259A:
	; 设置主片和从片的ICW1
	mov al, 011h
	out 020h, al
	call io_delay
	
	out 0A0h, al
	call io_delay
	
	; 设置主片和从片的ICW2
	; 20h（32）代表IRQ0~IRQ7的中断向量号是20h~27h
	mov al, 020h
	out 021h, al
	call io_delay
	
	; 28h（40）代表IRQ8~IRQ15的中断向量号是28h~2Fh
	mov al, 028h
	out 0A1h, al
	call io_delay
	
	; 设置主片的ICW3,004表示IR2对应从片
	mov al, 004h
	out 021h, al
	call io_delay
	
	; 设置从片的ICW3,002表示从片连主片的IR号是2
	mov al, 002h
	out 0A1h, al
	call io_delay
	
	; 设置主片的ICW4,1表示sequential模式、正常EOI，80x86模式
	mov al, 001h
	out 021h, al
	call io_delay
	
	; 设置从片的ICW4,1表示sequential模式、正常EOI，80x86模式
	out 0A1h, al
	call io_delay
	
	; 以下设置OCW1
	mov al, 11111110b ; 仅开启定时器中断
	out 021h, al
	call io_delay
	
	mov al, 11111111b
	out 0A1h, al
	call io_delay
	
	ret
	
io_delay:
	nop
	nop
	nop
	nop
	ret
	
_SpuriousHandler:
SpuriousHandler equ _SpuriousHandler - $$
	mov ah, 0Ch
	mov al, '!'
	mov [gs:((80 * 0 + 75) * 2)], ax
	jmp $
	iretd
	

SegCode32Len equ $ - LABEL_SEG_CODE32

[SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:
	mov ax, SelectorNormal
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	
	mov eax, cr0
	and	eax, 7FFFFFFEh
	mov cr0, eax
	
LABEL_GO_BACK_TO_REAL:
	jmp 0:LABEL_REAL_ENTRY
	
Code16Len equ $ - LABEL_SEG_CODE16